/*
 * @brief:
 * @Author: TzzzT
 * @Date: 2022-05-10 13:59:19
 * @LastEditTime: 2023-05-05 00:24:47
 * @LastEditors: TzzzT
 */

/////////////////////BLE/////////////////////
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/event_groups.h"
#include "esp_log.h"
#include "nvs.h"
#include "nvs_flash.h"
#include "string.h"

#include "my_ble_server.h"
#include "esp_gatt_defs.h"

#include "RCS_slave.h"
#include "RCS_ble_slave.h"
#include "RCS_scr.h"
#include "RCS_protocol.h"

static const char *BLE_TAG = "BLE_TAG";

static const char *SEND_TAG = "BLE_SEND";

static const char *RECV_TAG = "BLE_RECV";

extern rcs_slave_system_t rcsSystem;

/// tx dev///
extern TaskHandle_t txTaskHandle;

extern TaskHandle_t bleserverTaskHandle;
extern QueueHandle_t xUploadDataQueue;

static void dev_connected_cb(esp_bd_addr_t cli_bda)
{
    ESP_LOGI(BLE_TAG, " into dev_connected_cb");
    bool can_connect = false;
    if (rcsSystem.device.wait_new_master)
    {
        // 无主状态，可以连接，不开启广播。
        ESP_LOGI(BLE_TAG, "wait_new_master is 1, can connect");
        set_master_bda(cli_bda);
        can_connect = true;
    }
    else
    {
        // 判断是否是目标主机断开。
        if (memcmp(cli_bda, rcsSystem.device.cli_bda, 6) == 0)
        {
            // 是原来的主机，可以连接，不开启广播。
            ESP_LOGI(BLE_TAG, "the old master connect ");
            can_connect = true;
        }
        else
        {
            // 不允许其他主机连接,重新开启广播
            ESP_LOGI(BLE_TAG, "invalid master connect ");
            close_server();
            if (eTaskGetState(bleserverTaskHandle) == eSuspended)
            {
                ESP_LOGE(BLE_TAG, "vTaskResume( bleserverTaskHandle )");
                vTaskResume(bleserverTaskHandle);
            }
        }
    }
    if (can_connect)
    {
        rcs_stop_advertise();
        rcsSystem.device.is_connect_master = INITING_BLE;
        rcsSystem.device.wait_new_master = false;
        // 恢复蓝牙任务
        // vTaskDelay(pdMS_TO_TICKS(1200));
        if (eTaskGetState(bleserverTaskHandle) == eSuspended)
        {
            ESP_LOGE(BLE_TAG, "vTaskResume( bleserverTaskHandle )");
            vTaskResume(bleserverTaskHandle);
        }
    }
}

static void client_disconnected_cb(esp_bd_addr_t cli_bda)
{
    ESP_LOGI(BLE_TAG, " into client_disconnected_cb");
    esp_log_buffer_hex(BLE_TAG, cli_bda, 6);
    rcsSystem.device.is_connect_master = DISCONNECT_BLE;
    rcsSystem.device.wait_new_master = false;
    if (eTaskGetState(bleserverTaskHandle) == eSuspended)
    {
        ESP_LOGE(BLE_TAG, "vTaskResume( bleserverTaskHandle )");
        vTaskResume(bleserverTaskHandle);
    }
}

/*
 */
static void client_write_cb(esp_bd_addr_t bda, uint8_t *buf, uint8_t buf_len)
{
    ESP_LOGI(RECV_TAG, "client_write_cb");
    analyse_master_package(buf, buf_len);
}

static void ble_server_cb_register(void)
{
    server_func_t *fun = get_server_func_p();
    fun->cli_conn_cb = dev_connected_cb;
    fun->cli_disconn_cb = client_disconnected_cb;
    fun->cli_write_cb = client_write_cb;
}

// 上电后能取到主机地址代表不接受新连接，需要长按使能新连接标志。
void rcs_ble_init(void)
{
    ble_server_cb_register();
    // 开启蓝牙底层有限状态机
    ble_server_init();
    rcsSystem.device.is_connect_master = DISCONNECT_BLE;
    esp_err_t err = get_master_bda_from_nvs();
    if (err != ESP_OK)
    {
        clean_master_bda();
        rcsSystem.device.wait_new_master = true;
    }
    else
    {
        rcsSystem.device.wait_new_master = false;
    }
}

void rcs_start_advertise(bool is_allow)
{
    char poi_name_y[] = "GUN-POI-Y";
    char poi_name_n[] = "GUN-POI-N";
    char scr_name_y[] = "GUN-SCR-Y";
    char scr_name_n[] = "GUN-SCR-N";

    if (rcsSystem.device.is_hold_scr)
    {
        if (is_allow)
        {
            set_adv_device_name((uint8_t *)scr_name_y, strlen(scr_name_y));
        }
        else
        {
            set_adv_device_name((uint8_t *)scr_name_n, strlen(scr_name_n));
        }
    }
    else
    {
        if (is_allow)
        {
            set_adv_device_name((uint8_t *)poi_name_y, strlen(poi_name_y));
        }
        else
        {
            set_adv_device_name((uint8_t *)poi_name_n, strlen(poi_name_n));
        }
    }
}

bool rcs_is_advertising(void)
{
    return is_server_advertising();
}

void rcs_stop_advertise(void)
{
    ESP_LOGE(BLE_TAG, "rcs_stop_advertise");
    stop_server_advertising();
}

esp_err_t rcs_notify_client(uint8_t *buf, uint16_t buf_len)
{
    esp_err_t ret = ESP_FAIL;
    if (rcsSystem.device.is_connect_master == DISCONNECT_BLE || buf_len == 0 || buf == NULL)
    {
        return ret;
    }
    ESP_LOGE(SEND_TAG, "len:%d", buf_len);
    ret = notify_client(buf, buf_len);
    return ret;
}

void set_master_bda(bd_addr_t bda)
{
    memcpy(rcsSystem.device.cli_bda, bda, 6);
    store_master_bda_to_nvs();
}

void clean_master_bda(void)
{
    uint8_t dummy_bda[6] = {0};
    memcpy(rcsSystem.device.cli_bda, dummy_bda, 6);
}

#define MASTER_BDA_KEY "master_bda"

esp_err_t store_master_bda_to_nvs(void)
{
    nvs_handle bleNvsHandle;
    size_t len = BLUETOOTH_DEVICE_ADDR_LEN;
    esp_err_t err;

    err = nvs_open("ble_config", NVS_READWRITE, &bleNvsHandle);
    if (err != ESP_OK)
    {
        printf("Error (%s) opening NVS bleNvsHandle!\n", esp_err_to_name(err));
        return err;
    }
    esp_log_buffer_hex(BLE_TAG, rcsSystem.device.cli_bda, sizeof(bd_addr_t));
    err = nvs_set_blob(bleNvsHandle, MASTER_BDA_KEY, rcsSystem.device.cli_bda, len);
    if (err != ESP_OK)
    {
        printf("store_remote_bda_to_nvs failed, err(%s)\n", esp_err_to_name(err));
        return err;
    }
    else
    {
        ESP_LOGI(BLE_TAG, "store_remote_bda_to_nvs successfully");
    }
    err = nvs_commit(bleNvsHandle);
    nvs_close(bleNvsHandle);
    return err;
}

esp_err_t get_master_bda_from_nvs(void)
{
    nvs_handle bleNvsHandle;
    esp_err_t err = nvs_open("ble_config", NVS_READWRITE, &bleNvsHandle);
    if (err != ESP_OK)
    {
        printf("Error (%s) opening NVS bleNvsHandle!\n", esp_err_to_name(err));
        return err;
    }
    size_t len = BLUETOOTH_DEVICE_ADDR_LEN;
    uint8_t dummy_bda[6] = {0};
    err = nvs_get_blob(bleNvsHandle, MASTER_BDA_KEY, dummy_bda, &len);
    if (err != ESP_OK)
    {
        printf("get_bda_from_nvs failed, err(%s)\n", esp_err_to_name(err));
        return err;
    }
    uint8_t zero_bda[6] = {0};
    if (memcmp(zero_bda, dummy_bda, 6) == 0)
    {
        ESP_LOGI(BLE_TAG, "bda is zero");
        err = ESP_ERR_NOT_FOUND;
        return err;
    }
    ESP_LOGI(BLE_TAG, "get bda");
    esp_log_buffer_hex(BLE_TAG, dummy_bda, 6);
    memcpy(rcsSystem.device.cli_bda, dummy_bda, 6);
    err = nvs_commit(bleNvsHandle);
    nvs_close(bleNvsHandle);
    return err;
}
